home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / bootp.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  9KB  |  376 lines

  1. /*
  2.  * Center for Information Technology Integration
  3.  *           The University of Michigan
  4.  *                    Ann Arbor
  5.  *
  6.  * Dedicated to the public domain.
  7.  * Send questions to info@citi.umich.edu
  8.  *
  9.  * BOOTP is documented in RFC 951 and RFC 1048
  10.  * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
  11.  */
  12.  
  13.  
  14. #include <time.h>
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "socket.h"
  18. #include "netuser.h"
  19. #include "udp.h"
  20. #include "iface.h"
  21. #include "ip.h"
  22. #include "internet.h"
  23. #include "domain.h"
  24. #include "rip.h"
  25. #include "cmdparse.h"
  26. #include "bootp.h"
  27.  
  28. static int bootp_rx __ARGS((struct iface *ifp,struct mbuf *bp));
  29. static void ntoh_bootp __ARGS((struct mbuf **bpp,struct bootp *bootpp));
  30. static int mask2width __ARGS((int32 mask));
  31.  
  32. #define BOOTP_TIMEOUT    30        /* Time limit for booting       */
  33. #define BOOTP_RETRANS    5        /* The inteval between sendings */
  34.  
  35. #ifdef    BOOTP
  36. int WantBootp = 0;
  37. #endif
  38. static int SilentStartup = 0;
  39.  
  40. int
  41. #ifdef PROTOTYPES
  42. dobootp(int argc,char **argv,void *p)
  43. #else
  44. dobootp(argc,argv,p)
  45. int argc;
  46. char *argv[];
  47. void *p;
  48. #endif
  49. {
  50.     struct iface *ifp = NULLIF;
  51.     struct socket lsock, fsock;
  52.     struct mbuf *bp;
  53.     struct udp_cb *bootp_cb;
  54.     register char *cp;
  55.     time_t        now,        /* The current time (seconds)   */
  56.               starttime,    /* The start time of sending BOOTP */
  57.               lastsendtime;    /* The last time of sending BOOTP  */
  58.     int i;
  59.  
  60.     if(argc < 2)            /* default to the first interface */
  61.         ifp = Ifaces;
  62.     else {
  63.         for(i = 1; i != argc; ++i){
  64.             
  65.             if((ifp = if_lookup(argv[i])) != NULLIF) 
  66.                 continue;
  67.             else if(strncmp(argv[i], "silent", strlen(argv[i])) == 0)
  68.                 SilentStartup = 1;
  69.             else if(strncmp(argv[i], "noisy", strlen(argv[i])) == 0)
  70.                 SilentStartup = 0;
  71.             else {
  72.                 tprintf("bootp [net_name] [silent] [noisy]\n");
  73.                 return 1;
  74.             }
  75.         }
  76.     }
  77.  
  78.     if(ifp == NULLIF)
  79.         return 0;
  80.     
  81.     lsock.address = ifp->addr;
  82.     lsock.port = IPPORT_BOOTPC;
  83.  
  84.     bootp_cb = open_udp(&lsock,NULLVFP((struct iface*,struct udp_cb*,int)));
  85.  
  86.     fsock.address = ifp->broadcast;
  87.     fsock.port = IPPORT_BOOTPS;
  88.  
  89.       /* Get boot starting time */
  90.       time(&starttime);
  91.       lastsendtime = 0;
  92.  
  93.       /* Send the bootp request packet until a response is received or time
  94.        out */
  95.       for(;;){
  96.  
  97.         /* Allow bootp packets should be passed through iproute. */
  98.         WantBootp = 1;
  99.  
  100.         /* Get the current time */
  101.         time(&now);
  102.  
  103.         /* Stop, if time out */
  104.         if(now - starttime >= BOOTP_TIMEOUT){
  105.             tprintf("bootp: timed out, values not set\n");
  106.             break;
  107.         }
  108.  
  109.         /* Don't flood the network, send in intervals */
  110.         if(now - lastsendtime > BOOTP_RETRANS){
  111.             if(!SilentStartup) tprintf("Requesting...\n");
  112.  
  113.             /* Allocate BOOTP packet and fill it in */
  114.             if((bp = alloc_mbuf(sizeof(struct bootp))) == NULLBUF)
  115.                 break;
  116.  
  117.             cp = bp->data;        /* names per the RFC: */
  118.             *cp++ = BOOTREQUEST;        /* op */
  119.             *cp++ = ifp->iftype->type;    /* htype */
  120.             *cp++ = ifp->iftype->hwalen;    /* hlen */
  121.             *cp++ = 0;            /* hops */
  122.             cp = put32(cp,(int32) now);    /* xid */
  123.             cp = put16(cp, now - starttime);/* secs */
  124.             cp = put16(cp, 0);        /* unused */
  125.             cp = put32(cp, ifp->addr);    /* ciaddr */
  126.             cp = put32(cp, 0L);        /* yiaddr */
  127.             cp = put32(cp, 0L);        /* siaddr */
  128.             cp = put32(cp, 0L);        /* giaddr */
  129.             memcpy(cp, ifp->hwaddr, (size_t)ifp->iftype->hwalen);
  130.             cp += 16;            /* chaddr */
  131.             memset(cp, 0, 64);        /* sname */
  132.             cp += 64;
  133.             memset(cp, 0, 128);        /* file */
  134.             cp += 128;
  135.             memset(cp, 0, 64);        /* vend */
  136.             cp += 64;
  137.             bp->cnt = cp - bp->data;
  138.             /* assert(bp->cnt == BOOTP_LEN) */
  139.  
  140.             /* Send out one BOOTP Request packet as a broadcast */
  141.             send_udp(&lsock, &fsock,0,0,bp,bp->cnt,0,0);
  142.  
  143.             lastsendtime = now;
  144.         }
  145.  
  146.         /* Give other tasks a chance to run. */
  147.         pwait(NULL);
  148.  
  149.         /* Test for and process any replies */
  150.         if(recv_udp(bootp_cb, &fsock, &bp) > -1){
  151.             if(bootp_rx(ifp,bp))
  152.                 break;
  153.         } else if(Net_error != WOULDBLK){
  154.             tprintf("bootp: Net_error %d, no values set\n",
  155.                  Net_error);
  156.             break;
  157.         }
  158.       }
  159.  
  160.     WantBootp = 0;
  161.     del_udp(bootp_cb);
  162.     return 0;
  163. }
  164.  
  165. /* Process BOOTP input received from 'interface'. */
  166. static int
  167. bootp_rx(ifp,bp)
  168. struct iface *ifp;
  169. struct mbuf *bp;
  170. {
  171.     int         ch;
  172.     int            count;
  173.     int32         gateway = 0;
  174.     int32         nameserver = 0;
  175.     int32         broadcast, netmask;
  176.     struct route     *rp;
  177.     struct bootp    reply;
  178.     char        *cp;
  179.  
  180.     if(len_p(bp) != sizeof(struct bootp)){
  181.         free_p(bp);
  182.         return 0;
  183.     }
  184.     ntoh_bootp(&bp, &reply);
  185.     free_p(bp);
  186.  
  187.     if(reply.op != BOOTREPLY) 
  188.         return 0;
  189.  
  190.     if(!SilentStartup)
  191.         tprintf("Network %s configured:\n", ifp->name);
  192.  
  193.     if(ifp->addr == 0){
  194.         Ip_addr = (int) reply.yiaddr.s_addr;    /* yiaddr */
  195.         ifp->addr =  reply.yiaddr.s_addr;    /* yiaddr */
  196.         if(!SilentStartup)
  197.             tprintf("     IP address: %s\n",  
  198.         inet_ntoa(ifp->addr));
  199.     }
  200.  
  201.  
  202.     /* now process the vendor-specific block, check for cookie first. */
  203.     cp = reply.vend;
  204.     if(get32(cp) != 0x63825363L){
  205.         printf("Invalid magic cookie.\n");
  206.         return(0);
  207.     }
  208.  
  209.     cp += 4;
  210.     while(((ch = *cp) != BOOTP_END) && (++cp < (reply.vend + 64))) 
  211.         switch(ch){
  212.         case BOOTP_PAD:        /* They're just padding */
  213.             continue;
  214.         case BOOTP_SUBNET:    /* fixed length, 4 octets */
  215.             cp++;        /* moved past length */
  216.  
  217.             /* Set the netmask */
  218.                 /* Remove old entry if it exists */
  219.             netmask = get32(cp);
  220.             cp += 4;
  221.  
  222.                 rp = rt_blookup(ifp->addr & ifp->netmask,(unsigned)mask2width(ifp->netmask));
  223.                 if(rp != NULLROUTE)
  224.                         rt_drop(rp->target,rp->bits);
  225.                 ifp->netmask = netmask;
  226.                 rt_add(ifp->addr,(unsigned)mask2width(ifp->netmask),0L,ifp,0L,0L,0);
  227.  
  228.             if(!SilentStartup)
  229.                 tprintf("     Subnet mask: %s\n", inet_ntoa(netmask));
  230.             
  231.             /* Set the broadcast */
  232.             broadcast = ifp->addr | ~(ifp->netmask);
  233.                 rp = rt_blookup(ifp->broadcast,32);
  234.                 if(rp != NULLROUTE && rp->iface == ifp)
  235.                         rt_drop(ifp->broadcast,32);
  236.                 ifp->broadcast = broadcast;
  237.                 rt_add(ifp->broadcast,32,0L,ifp,1L,0L,1);
  238.             
  239.             if(!SilentStartup)
  240.                 tprintf("     Broadcast: %s\n", inet_ntoa(broadcast));
  241.  
  242.             break;
  243.         case BOOTP_HOSTNAME:
  244.             count = (int) *cp;
  245.             cp++;
  246.  
  247.             if(Hostname != NULLCHAR)
  248.                 free(Hostname);
  249.             Hostname = mallocw((unsigned)count);
  250.             strncpy(Hostname, cp, (size_t)count);
  251.             cp += count;
  252.  
  253.             if(!SilentStartup)
  254.                 tprintf("     Hostname: %s\n", Hostname);
  255.             break;
  256.         case BOOTP_DNS:
  257.             count = (int) *cp;
  258.             cp++;
  259.  
  260.             while(count){
  261.                 nameserver = get32(cp);
  262.                 add_nameserver(nameserver);
  263.                 if(!SilentStartup)
  264.                     tprintf("     Nameserver: %s\n", inet_ntoa(nameserver));
  265.                 cp += 4;
  266.                 count -= 4;
  267.             }
  268.             break;
  269.         case BOOTP_GATEWAY:
  270.             count = (int) *cp;
  271.             cp++;
  272.  
  273.             gateway = get32(cp);
  274.  
  275.             /* Add the gateway as the default */
  276.             rt_add(0,0,gateway,ifp,1,0,0);
  277.  
  278.             if(!SilentStartup)
  279.                 tprintf("     Default gateway: %s\n", inet_ntoa(gateway));
  280.             cp += count;
  281.             break;
  282.         default:        /* variable field we don't know about */
  283.             count = (int) *cp;
  284.             cp++;
  285.  
  286.             cp += count;
  287.             break;
  288.     }
  289.  
  290.     rt_add(ifp->addr,(unsigned)mask2width(ifp->netmask),0L,ifp,1,0,0);
  291.  
  292.     return(1);
  293. }
  294.  
  295.  
  296. static void
  297. ntoh_bootp(bpp, bootpp)
  298. struct mbuf **bpp;
  299. struct bootp *bootpp;
  300. {
  301.     bootpp->op = pullchar(bpp);                     /* op */
  302.     bootpp->htype = pullchar(bpp);            /* htype */
  303.     bootpp->hlen = pullchar(bpp);            /* hlen */
  304.     bootpp->hops = pullchar(bpp);            /* hops */
  305.     bootpp->xid = pull32(bpp);            /* xid */
  306.     bootpp->secs = pull16(bpp);            /* secs */
  307.     bootpp->unused = pull16(bpp);            /* unused */
  308.     bootpp->ciaddr.s_addr = pull32(bpp);        /* ciaddr */
  309.     bootpp->yiaddr.s_addr = pull32(bpp);        /* ciaddr */
  310.     bootpp->siaddr.s_addr = pull32(bpp);        /* siaddr */
  311.     bootpp->giaddr.s_addr = pull32(bpp);        /* giaddr */
  312.     pullup(bpp, bootpp->chaddr, 16);        /* chaddr */
  313.     pullup(bpp, bootpp->sname, 64);        /* sname */
  314.     pullup(bpp, bootpp->file, 128);        /* file name */
  315.     pullup(bpp, bootpp->vend, 64);            /* vendor */
  316. }
  317.  
  318.  
  319.  
  320. #ifdef    BOOTP
  321.  
  322. int
  323. bootp_validPacket(ip, bpp)
  324. struct ip *ip;
  325. struct mbuf **bpp;
  326. {
  327.     struct udp udp;
  328.     struct pseudo_header ph;
  329.     int status;
  330.  
  331.  
  332.     /* Must be a udp packet */
  333.     if(ip->protocol !=  UDP_PTCL) 
  334.         return 0;
  335.  
  336.     /* Invalid if packet is not the right size */
  337.     if(len_p(*bpp) != (sizeof(struct udp) + sizeof(struct bootp)))
  338.         return 0;
  339.  
  340.     /* Invalid if not a udp bootp packet */
  341.     ntohudp(&udp, bpp);
  342.  
  343.     status = (udp.dest == IPPORT_BOOTPC) ? 1 : 0;
  344.     
  345.     /* Restore packet, data hasn't changed */
  346.         /* Create pseudo-header and verify checksum */
  347.         ph.source = ip->source;
  348.         ph.dest = ip->dest;
  349.         ph.protocol = ip->protocol;
  350.         ph.length = ip->length - IPLEN - ip->optlen;
  351.  
  352.     *bpp = htonudp(&udp, *bpp, &ph);
  353.  
  354.     return status;
  355. }
  356. #endif
  357.  
  358. /* Given a network mask, return the number of contiguous 1-bits starting
  359.  * from the most significant bit.
  360.  */
  361. static int
  362. mask2width(mask)
  363. int32 mask;
  364. {
  365.         int width,i;
  366.  
  367.         width = 0;
  368.         for(i = 31;i >= 0;i--){
  369.                 if(!(mask & (1L << i)))
  370.                         break;
  371.                 width++;
  372.         }
  373.         return width;
  374. }
  375.  
  376.